home *** CD-ROM | disk | FTP | other *** search
/ Games of Daze / Infomagic - Games of Daze (Summer 1995) (Disc 1 of 2).iso / x2ftp / msdos / source / scale / xscale1.asm < prev   
Encoding:
Assembly Source File  |  1993-04-29  |  12.0 KB  |  236 lines

  1. ;=========================================================================
  2. ; XSCALE1.ASM by John A. Slagel, jas37876@uxa.cso.uiuc.edu
  3. ; This is some code to do bitmap scaling in VGA Mode X.  It can scale a
  4. ; bitmap of any size down to 2 pixels wide, or up to thousands of pixels
  5. ; wide.  It performs complete clipping, with only a small constant amount
  6. ; of time to clip, no matter how huge the image is.  It draws column by
  7. ; column to reduce the number of plane switches, which are slow. The inner
  8. ; column loop has been optimized for no memory accesses, except to read or
  9. ; write a pixel.  This uses MASM 5.1 features, and can be compiled in any
  10. ; memory model by changing the .MODEL line, but make sure that you always
  11. ; pass a far pointer to the bitmap data, regardless of memory model.
  12. ; C-callable as:
  13. ;   void XSCALE1( int X, int Y, int DW, int DY,
  14. ;                     int SW, int SH, void far * Bitmap );
  15. ; X,Y   are the upper left-hand coordinates of where to draw the bitmap.
  16. ; DW,DH are the width and height of the SCALEed bitmap
  17. ; SW,SH are the width and height of the source bitmap.
  18. ; Bitmap is a pointer to the bitmap bits.
  19. ;
  20. ;==========================================================================
  21. .MODEL LARGE, C
  22. .386
  23.  
  24. .DATA
  25. SC_INDEX1   EQU 03C4h               ; Port number of VGA Sequencer Reg
  26. SC_INDEX2   EQU 03C5h               ; Port number of VGA Seqeuncer Data
  27. MAP_MASK    EQU 2                   ; Map Mask register index into Sequencer
  28.  
  29. ClipLt      DW  20                  ; Left clipping boundry
  30. ClipRt      DW  300                 ; Right clipping boundry
  31. ClipTp      DW  20                  ; Top clipping boundry
  32. ClipBt      DW  190                 ; Bottom clipping boundry
  33. ModeXseg    DW  0A000h              ; Current VGA segment
  34.  
  35. .CODE
  36.  
  37. XSCALE1 PROC FAR USES DS DI SI, DestX:WORD, DestY:WORD,                 \
  38.                                     DestWidth:WORD, DestHeight:WORD,        \
  39.                                     SourceWidth:WORD, SourceHeight:WORD,    \
  40.                                     Bitmap:FAR PTR
  41. LOCAL   DecisionX:WORD, DecisionY:WORD, ClippedWidth:WORD, ClippedHeight:WORD
  42.  
  43.         cmp     DestWidth, 2        ; If destination width is less than 2
  44.         jl      Done                ;     then don't draw it.
  45.  
  46.         cmp     DestHeight, 2       ; If destination height is less than 2
  47.         jl      Done                ;     then don't draw it.
  48.  
  49.         mov     ax, DestY           ; If it is completely below the
  50.         cmp     ax, ClipBt          ; lower clip bondry,
  51.         jg      Done                ;     then don't draw it.
  52.  
  53.         add     ax, DestHeight      ; If it is above clip boundries
  54.         dec     ax                  ;     then don't draw it.
  55.         cmp     ax, ClipTp
  56.         jl      Done
  57.  
  58.         mov     ax, DestX           ; If it is to the right of the
  59.         mov     cx, ClipRt          ; right clip boundry
  60.         cmp     ax, ClipRt          ;     then don't draw it.
  61.         jg      Done
  62.  
  63.         add     ax, DestWidth       ; If it is completely to the left
  64.         dec     ax                  ; of the left clip boundry,
  65.         cmp     ax, ClipLt          ;     then don't draw it.
  66.         jl      Done
  67.  
  68.         les     si, Bitmap          ; Make DS:SI point to bitmap data
  69.  
  70.         mov     ax, DestWidth       ; ClippedWidth is initially set to
  71.         mov     ClippedWidth, ax    ; the requested dest width.
  72.  
  73.         shl     ax,1                ; Initialize the X decision var
  74.         neg     ax                  ; to be -2*DestWidth
  75.         mov     DecisionX, ax       ;
  76.  
  77.         mov     ax, DestHeight      ; ClippedHeight is initially set to
  78.         mov     ClippedHeight, ax   ; the requested dest size.
  79.  
  80.         shl     ax,1                ; Initialize the Y decision var
  81.         neg     ax                  ; to be -2*DestHeight
  82.         mov     DecisionY, ax       ;
  83.  
  84.         movsx   eax, ClipTp         ; If Y is below the top
  85.         mov     edx, eax            ; clipping boundry, then we don't
  86.         sub     dx, DestY           ; need to clip the top, so we can
  87.         js      NoTopClip           ; jump over the clipping stuff.
  88.  
  89.         mov     DestY, ax           ; This block performs clipping on the
  90.         sub     ClippedHeight, dx   ; top of the bitmap.  I have heavily
  91.         movsx   ecx, SourceHeight   ; optimized this block to use only 4
  92.         imul    ecx, edx            ; 32-bit registers, so I'm not even
  93.         mov     eax, ecx            ; gonna try to explain what it's doing.
  94.         mov     edx, 0              ; But I can tell you what results from
  95.         movsx   ebx, DestHeight     ; this:  The DecisionY var is updated
  96.         idiv    ebx                 ; to start at the right clipped row.
  97.         movsx   edx, SourceWidth    ; Y is moved to the top clip
  98.         imul    edx, eax            ; boundry. ClippedHeight is lowered since
  99.         add     si, dx              ; we won't be drawing all the requested
  100.         imul    eax, ebx            ; rows.  SI is changed to point over
  101.         sub     ecx, eax            ; the bitmap data that is clipped off.
  102.         sub     ecx, ebx            ;
  103.         shl     ecx, 1              ;
  104.         mov     DecisionY, cx       ; <end of top clipping block >
  105.  
  106. NoTopClip:
  107.         mov     ax, DestY           ; If the bitmap doesn't extend over the
  108.         add     ax, ClippedHeight   ; bottom clipping boundry, then we
  109.         dec     ax                  ; don't need to clip the bottom, so we
  110.         cmp     ax, ClipBt          ; can jump over the bottom clip code.
  111.         jle     NoBottomClip        ;
  112.  
  113.         mov     ax, ClipBt          ; Clip off the bottom by reducing the
  114.         sub     ax, DestY           ; ClippedHeight so that the bitmap won't
  115.         inc     ax                  ; extend over the lower clipping
  116.         mov     ClippedHeight, ax   ; boundry.
  117.  
  118. NoBottomClip:
  119.         movsx   eax, ClipLt         ; If X is to the left of the
  120.         mov     edx, eax            ; top clipping boundry, then we don't
  121.         sub     dx, DestX           ; need to clip the left, so we can
  122.         js      NoLeftClip          ; jump over the clipping stuff.
  123.  
  124.         mov     DestX, ax           ; This block performs clipping on the
  125.         sub     ClippedWidth, dx    ; left of the bitmap.  I have heavily
  126.         movsx   ecx, SourceWidth    ; optimized this block to use only 4
  127.         imul    ecx, edx            ; 32-bit registers, so I'm not even
  128.         mov     eax, ecx            ; gonna try to explain what it's doing.
  129.         mov     edx, 0              ; But I can tell you what results from
  130.         movsx   ebx, DestWidth      ; this:  The DecisionX var is updated
  131.         idiv    ebx                 ; to start at the right clipped column.
  132.         add     si, ax              ; X is moved to the left clip
  133.         imul    eax, ebx            ; boundry. ClippedWidth is reduced since
  134.         sub     ecx, eax            ; we won't be drawing all the requested
  135.         sub     ecx, ebx            ; cols.  SI is changed to point over
  136.         shl     ecx, 1              ; the bitmap data that is clipped off.
  137.         mov     DecisionX, cx       ; <end of left clipping block >
  138.  
  139. NoLeftClip:
  140.         mov     ax, DestX           ; If the bitmap doesn't extend over the
  141.         add     ax, ClippedWidth    ; right clipping boundry, then we
  142.         dec     ax                  ; don't need to clip the right, so we
  143.         cmp     ax, ClipRt          ; can jump over the right clip code.
  144.         jle     NoClipRight         ;
  145.  
  146.         mov     ax, ClipRt          ; Clip off the right by reducing the
  147.         sub     ax, DestX           ; ClippedWidth so that the bitmap won't
  148.         inc     ax                  ; extend over the right clipping
  149.         mov     ClippedWidth, ax    ; boundry.
  150.  
  151.         ;Calculate starting video address
  152. NoClipRight:
  153.         mov     ax, ModeXseg        ; We are going to set DS:DI to point
  154.         mov     ds, ax              ; to the place to start drawing in
  155.         mov     di, DestY           ; VGA memory. This code sets DS to the
  156.         imul    di, 80              ; VGA segment, which is usually at
  157.         mov     ax, DestX           ; segment 0A000. The offset DI is
  158.         mov     cx, ax              ; calculated by:
  159.         shr     ax, 2               ;     DI = Y*80+X/2
  160.         add     di, ax              ; DS:DI is ready!
  161.  
  162.         mov     dx, SC_INDEX1       ; Point the VGA Sequencer to the Map
  163.         mov     al, MAP_MASK        ; Mask register, so that we only need
  164.         out     dx, al              ; to send out 1 byte per column.
  165.  
  166.         inc     dx                  ; Move to the Sequencer's Data register.
  167.         and     cx, 3               ; Calculate the starting plane. This is
  168.         mov     al, 11h             ; just:
  169.         shl     al, cl              ; Plane =  (11h << (X AND 3))
  170.         out     dx, al              ; Select the first plane.
  171.  
  172.         ALIGN   4                   ; Since this point gets jumped to a lot,
  173.                                     ; make sure that it is DWORD aligned.
  174. RowLoop:
  175.         push    si                  ; Save the starting source index
  176.         push    di                  ; Save the starting dest index
  177.         push    ax                  ; Save the current plane mask
  178.         push    bp                  ; Save the current base pointer
  179.  
  180.         mov     ax, ClippedHeight   ; Use AL for row counter (0-239)
  181.         mov     bx, DecisionY       ; Use BX for decision variable
  182.         mov     cx, SourceWidth     ; Use CX for source width
  183.         mov     dx, SourceHeight    ; Use DX for source height * 2
  184.         shl     dx, 1
  185.         mov     bp, DestHeight      ; Use BP for dest height * 2
  186.         shl     bp, 1
  187.         mov     ah, es:[si]         ; Get the first source pixel
  188.  
  189.         ALIGN   4                   ; Common jump point... align for speed.
  190. ColumnLoop:
  191.         mov     ds:[di], ah         ; Draw a pixel
  192.         dec     al                  ; Decrement line counter
  193.         jz      DoneWithCol         ; See if we're done with this column
  194.         add     di, 80              ; Go on to the next screen row
  195.         add     bx, dx              ; Increment the decision variable
  196.         js      ColumnLoop          ; Draw this source pixel again
  197.  
  198. IncSourceRow:
  199.         add     si, cx              ; Move to the next source pixel
  200.         sub     bx, bp              ; Decrement the decision variable
  201.         jns     IncSourceRow        ; See if we need to skip another source pixel
  202.         mov     ah, es:[si]         ; Get the next source pixel
  203.         jmp     ColumnLoop          ; Start drawing this pixel
  204.  
  205. DoneWithCol:
  206.         pop     bp                  ; Restore BP to access variables
  207.         pop     ax                  ; Restore AL = plane mask
  208.         pop     di                  ; Restore DI to top row of screen
  209.         pop     si                  ; Restore SI to top row of source bits
  210.  
  211.         rol     al, 1               ; Move to next plane
  212.         adc     di, 0               ; Go on to next screen column
  213.         mov     dx, SC_INDEX2       ; Tell the VGA what column we're in
  214.         out     dx, al              ; by updating the map mask register
  215.  
  216.         shl     cx, 1               ; CX = SourceWidth * 2
  217.         mov     bx, DecisionX       ; Use BX for the X decision variable
  218.         add     bx, cx              ; Increment the X decision variable
  219.         js      NextCol             ; Jump if we're still in the same source col.
  220.         mov     dx, DestWidth       ; DX = W * 2
  221.         shl     dx, 1
  222. IncSourceCol:
  223.         inc     si                  ; Move to next source column
  224.         sub     bx, dx              ; Decrement X decision variable
  225.         jns     IncSourceCol        ; See if we skip another source column
  226. NextCol:
  227.         mov     DecisionX, bx       ; Free up BX for ColLoop
  228.         dec     ClippedWidth        ; If we're not at last column
  229.         jnz     RowLoop             ;    then do another column
  230. Done:
  231.         ret                         ; We're done!
  232.  
  233. XSCALE1     ENDP
  234.  
  235.             END
  236.